#ifndef __SOCKETMAN__
#define __SOCKETMAN__


#include "DLList.h"
#include "SocketBuf.h"
#include "SocketStruct.h"
#include "SocketMacros.h"
#include "SocketGlobals.h"
#include "SocketBase.h"

class SocketMan : public SocketBase
{ 
private:
  DLList< SocketStruct * >	sl;   // list of connected clients' sockets
  Pix				slp;  // position of iteration in this list
  int				rewound;  // boolean to indicate whether
					  // sockets are "rewound"
  SocketStruct * 		current_socket;
  SocketStruct *		last_accepted_socket;
  DLList< unsigned short >	pl;   // udp deleted port list

  SOCKET			listening_socket_fd;
  struct timeval		read_timeout;
  struct timeval		write_timeout;
  float				read_timeout_float;
  float				write_timeout_float;
  int				number_of_connections;
  int				limit_connections;
  int				use_sigio;
  unsigned short		udp_last_port;
  unsigned short		udp_base_port;

  void 				addToSocketList(SOCKET sock_fd, 
						unsigned short sock_port,
						unsigned long address);


  int 				createListeningSocket(unsigned short port);
  int				closeListeningSocket();
  int				closeConnectedSockets();

  int 				prevSocket();
  int 				deleteSocket();
  
  friend void                   handleSIGPIPE(int);
  friend class			AliveServer;

public:
  SocketMan(unsigned short port,
	    int user_read_timeout_secs = 1,
	    int user_read_timeout_usecs = 0,
	    int user_write_timeout_secs = 1,
	    int user_write_timeout_usecs = 0,
	    int user_quiet = 0,
	    int user_limit_connections = 0,
	    int user_use_sigio = 0,
	    int user_sys_v_signals = 0,
	    int user_use_udp = 0);
  ~SocketMan();

  int				acceptConnectionWithPoll();
  void 				rewindSockets();
  int 				nextSocket();

  // methods that allow user to do an external select()
  void				setFDSet(fd_set *fds);
  int				getPostSelectReadAction(fd_set *fds);

  // method which does an internal select (uses above methods)
  int				smartSelect();

  // Methods that operate on the current socket.
  // NOTE that memory is allocated INTERNALLY in all the read functions;
  // ALWAYS delete the returned object when done with it!
  // Example:
  // SocketBuf *sbuf;
  // sbuf = readWithTimeout();
  // if (sbuf) { /* use sbuf */ delete sbuf; }

  SocketBuf*			readWithPollAndTimeout();
  SocketBuf* 			readWithTimeout();
  SocketBuf* 			recoverFromReadError();
  int				writeWithTimeout(SocketBuf *sbuf);

  // Methods used for error handling by the user

  int				getLastMessage();

  // Utility methods

  int				getNumberOfConnections();
  void				cleanupUDPSockets();
  int				getUsingUDP();
  int				setUsingUDP(int on_or_off);

};

#endif
